package com.example.anno.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.text.MessageFormat;
import java.util.Arrays;
import java.util.stream.Collectors;

@Aspect
@Component
public class MetricAspect {

    private final StopWatch watch = new StopWatch();

    @Pointcut("@annotation(com.example.anno.aop.Metric)")
    public void pointCut() {}

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object returnValue ;
        try {
            String simpleName = joinPoint.getTarget().getClass().getSimpleName();
            String methodName = joinPoint.getSignature().getName();
            String message = MessageFormat.format("Calling {0}.{1}({2})",simpleName, methodName,
                    Arrays.stream(joinPoint.getArgs()).map(Object::toString).collect(Collectors.joining(",")));
            watch.start(message);
            returnValue = joinPoint.proceed();
        } catch (Throwable e) {
            watch.stop();
            throw new RuntimeException(e);
        }finally {
            watch.stop();
            String lastTaskName = watch.getLastTaskName();
            long millis = watch.getTotalTimeMillis();
            System.err.println(" -> [@Metric-Debug]:" + lastTaskName + ", Cost Time: " + millis + " ms");
        }

        return returnValue;
    }
}
